package com.fingard.crypto;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.spec.X509EncodedKeySpec;
import java.util.Enumeration;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

/**
 * Created by F on 2020/3/26.
 */
public class SignEncryptHelper {

    /**
     * 根据cer文件获取公钥
     * @param cerPath
     * @return
     */
    public static PublicKey getPubKeyByCerFile(String cerPath) {
        PublicKey publicKey = null;
        try {
            // 获得公钥
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            FileInputStream in = new FileInputStream(cerPath);
            // 生成一个证书对象并使用从输入流 inStream 中读取的数据对它进行初始化。
            Certificate c = cf.generateCertificate(in);
            publicKey = c.getPublicKey();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return publicKey;
    }

    /**
     * 从base64文件中获取公钥
     * @param baseStr
     * @return
     * @throws Exception
     */
    public static PublicKey getPubkeyByBase64Str(String baseStr)throws Exception{
        byte[] keybyte = Base64.decodeBase64(baseStr);
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keybyte);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
        return publicKey;
    }

    /**
     * 根据pfx文件获取密钥对
     * @param pfxPath
     * @param pswStr
     * @return
     * @throws Exception
     */
    public static KeyStore getKey(String pfxPath, String pswStr) throws Exception{
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        char[] pwdChar = pswStr.toCharArray();
        FileInputStream pfxFis = new FileInputStream(pfxPath);
        keyStore.load(pfxFis,pwdChar);
        return keyStore;
    }

    /**
     * 从密钥库中获取私钥
     * @param keyStore
     * @param alias
     * @param pwdStr
     * @return
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(KeyStore keyStore,String alias,String pwdStr)throws Exception{
       return  (PrivateKey) keyStore.getKey(alias,pwdStr.toCharArray());
    }

    /**
     * 从密钥库中获取私钥
     * @param keyStore
     * @param pwdStr
     * @return
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(KeyStore keyStore,String pwdStr)throws Exception{
        Enumeration enums = keyStore.aliases();
        if(enums.hasMoreElements()){
            return getPrivateKey(keyStore,(String)enums.nextElement(),pwdStr);
        }
        return null;
    }

    /**
     * 从密钥库中获取私钥
     * @param keyStore
     * @param alias
     * @return
     * @throws Exception
     */
    public static PublicKey getPublicKey(KeyStore keyStore,String alias) throws Exception{
        Certificate cert= keyStore.getCertificate(alias);
        return cert.getPublicKey();
    }

    public static PublicKey getPublicKey(KeyStore keyStore) throws Exception{
        Enumeration enums = keyStore.aliases();
        if(enums.hasMoreElements()){
            return getPublicKey(keyStore,(String)enums.nextElement());
        }
        return null;
    }

    /**
     * 对数据进行签名
     * @param bytes
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static byte[] sign(byte[] bytes,PrivateKey privateKey)throws Exception{
        Signature signature = Signature.getInstance("SHA1withRSA");
        signature.initSign(privateKey);
        signature.update(bytes);
        return signature.sign();
    }

    /**
     * 公钥加密
     * @param sourceData
     * @param publicKey
     * @return
     */
    public static byte[] doEncryptByRSA(byte[] sourceData,PublicKey publicKey){
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            return cipher.doFinal(sourceData);
        }catch (Exception ex){
            ex.printStackTrace();
        }
        return null;
    }

    public static String doEncryptByRSA2(byte[] sourceData,PublicKey publicKey){
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] encryptData =  cipher.doFinal(sourceData);
            return Base64.encodeBase64String(encryptData);
        }catch (Exception ex){
            ex.printStackTrace();
        }
        return null;
    }
    /**
     * 私钥解密
     * @param encryptedData
     * @param privateKey
     * @return
     */
    public static byte[] doDecryptByRSA(byte[] encryptedData,PrivateKey privateKey){
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE,privateKey);
            return cipher.doFinal(encryptedData);
        }catch (Exception ex){
            ex.getStackTrace();
        }
        return null;
    }

    /**
     * 私钥解密
     * @param encryptedData
     * @param privateKey
     * @return
     */
    public static String doDecryptByRSA2(byte[] encryptedData,PrivateKey privateKey){
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE,privateKey);
            byte[] decrypt = cipher.doFinal(encryptedData);
            return new String(decrypt);
        }catch (Exception ex){
            ex.getStackTrace();
        }
        return null;
    }


    /**
     * 对数据进行验签
     * @param plainByte
     * @param signByte
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static boolean verify(byte[] plainByte,byte[] signByte,PublicKey publicKey)throws Exception{
        Signature signature = Signature.getInstance("SHA1withRSA");
        signature.initVerify(publicKey);
        signature.update(plainByte);
        return signature.verify(signByte);
    }



    /**
     * 对数据进行压缩
     * @param bytes
     * @return
     */
    public static byte[] compressToByte(byte[] bytes) {
        if (bytes.length == 0) {
            return null;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        GZIPOutputStream gzip;
        try {
            gzip = new GZIPOutputStream(out);
            gzip.write(bytes);
            gzip.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return out.toByteArray();
    }

    /**
     * 对数据解压
     * @param bytes
     * @param encoding
     * @return
     */
    public static String uncompressToString(byte[] bytes, String encoding) {
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ByteArrayInputStream in = new ByteArrayInputStream(bytes);

        try {
            GZIPInputStream gunzip = new GZIPInputStream(in);
            byte[] buffer = new byte[256];
            int n;
            while ((n = gunzip.read(buffer)) >= 0) {
                out.write(buffer, 0, n);
            }
            return out.toString(encoding);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }








}
